package net.chenlin.dp.ids.client.filter;

import net.chenlin.dp.ids.client.config.PassportClientConfig;
import net.chenlin.dp.ids.client.manager.AuthCheckManager;
import net.chenlin.dp.ids.common.constant.GlobalErrorEnum;
import net.chenlin.dp.ids.common.constant.IdsConst;
import net.chenlin.dp.ids.common.entity.SessionData;
import net.chenlin.dp.ids.common.util.CommonUtil;
import net.chenlin.dp.ids.common.util.CookieUtil;
import net.chenlin.dp.ids.common.util.JsonUtil;
import net.chenlin.dp.ids.common.util.WebUtil;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * ids web过滤器
 * @author zcl<yczclcn@163.com>
 */
public class PassportWebAuthFilter implements Filter {

    private FilterConfig filterConfig;

    private PassportClientConfig clientConfig;

    private AuthCheckManager authCheckManager;

    public PassportWebAuthFilter(PassportClientConfig clientConfig, AuthCheckManager authCheckManager) {
        this.clientConfig = clientConfig;
        this.authCheckManager = authCheckManager;
    }

    @Override
    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }

    /**
     * 过滤器链
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        HttpServletResponse servletResponse = (HttpServletResponse) response;
        String servletPath = servletRequest.getServletPath();
        String accessPolicy = clientConfig.matchAccessPolicy(servletPath);

        // 登出请求
        if (IdsConst.LOGOUT_URL.equals(servletPath)) {
            // 删除cookie
            CookieUtil.remove(servletRequest, servletResponse,
                    clientConfig.getAuthIdCookieName(), clientConfig.getCookieDomain());
            // 跳转登出地址
            String serviceUrl = request.getParameter(IdsConst.REDIRECT_KEY);
            if (CommonUtil.strIsEmpty(serviceUrl)) {
                serviceUrl = clientConfig.getServerName();
            }
            String logoutUrl = clientConfig.getServLogoutUrl(serviceUrl);
            servletResponse.sendRedirect(servletResponse.encodeRedirectURL(logoutUrl));
            return;
        }

        // 匿名请求，访问策略为ANON_ACCESS
        if (IdsConst.ANON_ACCESS_POLICY.equals(accessPolicy)) {
            chain.doFilter(request, response);
            return;
        }
        // 登录校验：从cookie，header，param中获取sessionId
        String clientSessionId = getSessionId(servletRequest);
        SessionData sessionData = authCheckManager.checkClientSession(clientSessionId, IdsConst.LOGIN_TYPE_WEB);
        if (sessionData == null) {
            // 删除cookie
            CookieUtil.remove(servletRequest, servletResponse, clientConfig.getAuthIdCookieName(),
                    clientConfig.getCookieDomain());
        } else {
            // sessionId写cookie
            CookieUtil.set(servletResponse, clientConfig.getAuthIdCookieName(), clientSessionId,
                    clientConfig.getCookieDomain(), sessionData.getRememberMe());
        }

        // 未登录，并且访问策略为AUTH_ACCESS
        if (sessionData == null && IdsConst.AUTH_ACCESS_POLICY.equals(accessPolicy)) {
            // ajax请求
            if (WebUtil.isAjax(servletRequest)) {
                Map<String, Object> anonRes = new HashMap<>(3);
                anonRes.put("authIntercept", true);
                anonRes.put("policy", "AUTH_ACCESS");
                anonRes.put("status", "ANONYMOUS");
                WebUtil.write(servletResponse, JsonUtil.toStr(anonRes));
                return;
            }
            // 重定向登录地址
            String redirectLoginUrl = clientConfig.getServLoginUrl(WebUtil.getReqUrl(servletRequest));
            servletResponse.sendRedirect(servletResponse.encodeRedirectURL(redirectLoginUrl));
            return;
        }

        // 登录成功，或者访问策略为 ROUTER_ACCESS
        request.setAttribute(IdsConst.SESSION_KEY, sessionData);
        // 非记住密码类型session，更新session过期时间
        if (sessionData != null && !sessionData.getRememberMe()) {
            authCheckManager.refreshWebSession(servletRequest);
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        this.filterConfig = null;
    }

    /**
     * 获取sessionId
     * @param request
     * @return
     */
    private String getSessionId(HttpServletRequest request) {
        String cookieSessionId = CookieUtil.getVal(request, clientConfig.getAuthIdCookieName());
        if (CommonUtil.strIsNotEmpty(cookieSessionId)) {
            return cookieSessionId;
        }
        String paramSessionId = request.getParameter(IdsConst.SESSION_PARAM_KEY);
        if (CommonUtil.strIsNotEmpty(paramSessionId)) {
            return paramSessionId;
        }
        String headSessionId = request.getHeader(IdsConst.SESSION_PARAM_KEY);
        if (CommonUtil.strIsNotEmpty(headSessionId)) {
            return headSessionId;
        }
        return null;
    }

}
